#! /usr/bin/python
# -*- coding: utf-8 -*-

import mechanize
import BeautifulSoup
import re
import argparse
import datetime, sys, os, os.path, re, ConfigParser
from channels import channels_by_name, channels_by_ref

default_excludes = [u'Plus belle la vie', u'Top Models', u'Rani', u'Les feux de l\'amour', u'Scènes de ménages', u'Arabesque',
					u'Les Cordier, juge et flic', u'Rex', u'Protection rapprochée', u'Les craquantes', u'Inspecteur Barnaby',
					u'Alice Nevers, le juge est une femme', u'Les nouvelles filles d\'à côté', u'Alerte Cobra', u'Les mystères de l\'amour',
					u'Une femme d\'honneur', u'Les souvenirs de Sherlock Holmes', u'Amour, gloire et beauté',
					u'Avengers : l\'équipe des super héros !', u'Avengers : l\'équipe des super-héros', u'Avengers, l\'équipe des super-héros',
					u'Bateau de rêve', u'Batman : L\'alliance des héros', u'Batman, l\'alliance des héros', u'Better off Ted',
					u'Chante !', u'Coeur océan', u'Danger corruption', u'Des jours et des vies', u'Famille d\'accueil',
					u'Gossip Girl', u'H2O', u'Heartland', u'Heinrich George, un acteur envers et contre tout', u'Highlander',
					u'Human Target : la cible', u'La Vierge noire', u'La vie secrète d\'une ado ordinaire', u'Lasko : le protecteur',
					u'Le tuteur', u'Les Cavaliers de l\'aube', u'Les Cordier juge et flic', u'Les cavaliers de l\'aube',
					u'Maigret', u'Myster Mocky présente', u'Navarro', '']

default_channels = ['TF1', 'ARTE', 'D8', 'FRANCE 2', 'FRANCE 3', 'FRANCE 4', 'FRANCE 5', 'M6', 'NT1', 'RTS UN', 'RTS DEUX', 'W9', 'TMC', 'NRJ12', 'BFM TV', 'Gulli', 'France O']
#default_channels = ['ARTE', 'FRANCE 2', 'FRANCE 3', 'FRANCE 4', 'RTS UN', 'RTS DEUX']
base_delta = 15

br = mechanize.Browser()
br.set_proxies({'http': 'netgw01:8080'})
br.set_handle_robots(False)   # ignore robots
br.set_handle_refresh(False)  # can sometimes hang without this

def get_channel_list():
	channels_by_name = {}
	channels_by_ref = {}
	soup = BeautifulSoup.BeautifulSoup(br.open('http://www.programme-tv.com/chaine/toutes-les-chaines-television.html').read())
	l = soup.findAll("ul", attrs={"class": "list-chaine-full"})
	for l1 in l:
		l2 = l1.findAll('a')
		for l3 in l2:
			if args.debug: print l3
			c = {}
			i = l3.img
			img = i['src']
			page = l3['href']
			ref = int(l3['href'].split('/')[2])
			if ref==344:
				i['alt'] = 'France O'
			channels_by_name[i['alt'].lower()] = dict(img=img, page=page, ref=ref)
			channels_by_ref[ref] = dict(img=img, page=page, name=i['alt'])

	return channels_by_name, channels_by_ref

def get_program(url):
	program = {}
	page = br.open(url).read()
	soup = BeautifulSoup.BeautifulSoup(page)
	l = soup.find(itemprop='episode')
	if l:
		l1 = l.find(itemprop='name')
		if l1:
			program['episode_title'] = l1.text.strip()
	l = soup.find('div', 'block-programme-content')
	#print l.prettify()
	#print '###################################'
	l1 = l.find(id='infos-programme')
	#print l1.prettify()
	#print '###################################'
	l2 = l1.findAll('p', attrs={"class": re.compile('label-(.*)')})
	for l3 in l2:
		#print l3.prettify()
		l3d = dict(l3.attrs)
		field = l3d['class'][6:]
		if field == 'saison':
			l4 = l3.find(itemprop='name')
			if l4:
				program['saison'] = l4.text
			else:
				program['saison'] = ''
			l4 = l3.find(itemprop='episodeNumber')
			if l4:
				program['episode'] = l4.text
			else:
				program['episode'] = ''
		else:
			program[field] = l3.text;
		#print u'type: {0}\t value : {1}'.format(l3d['class'][6:], l3.text)
		#print '###################################'
	l2 = l1.find('p', 'programme-suite')
	if l2:
		suite = [x.strip() for x in l2.contents if (not isinstance(x, BeautifulSoup.Tag) and x != u' ')]
		for s in suite:
			s1 = s.split(' : ')
			if len(s1) > 1:
				key = s1[0].strip()
				value = ':'.join(s1[1:]).strip()
				program[key] = value
				suite.remove(s)
				program['programme-suite'] = suite;
	l = soup.find('div', 'block-programme-content-story')
	if l:
		program['story'] = l.text
	#print program
	return program
	#l = soup.find('div', 'programme-casting')

def get_program_list(channel, date, types, excludes):
	progs = []
	url = forge_channel_url(channel, date)
	page = br.open(url).read()
	#print page
	#print '###################################'

	soup = BeautifulSoup.BeautifulSoup(page)
	#print soup
	#print '###################################'
	l1 = soup.findAll("ul", "list-chaine")
	for l in l1:
		#print l
		#print l.prettyfy()
		ll = l.findAll('div', 'chaineprogblock')
		progs.extend(ll)
		#print len(ll)
		#print ll[0].prettify()
		#for l in ll:
		#print '###################################'
		#print l.prettify()
	#print len(progs)
	programs = []
	for p in progs:
		program = {}
		#print p.prettify()
		hd = dict(p.attrs)
		program['type'] = hd['class'].split()[1]
		if program['type'] not in types: continue
#		print p.a.text, type(p.a.text)
		if p.a.text in excludes: continue
#		for a in excludes:
#			print a
#			if a == p.a.text: continue
		program['channel'] = channel
		program['date'] = date
		program['title'] = p.a.text
		ha = dict(p.a.attrs)
		program['l_title'] = ha['title']
		program['url'] = ha['href']
		program.update(get_program('http://www.programme-tv.com' + program['url']))
		programs.append(program)
		#print hd['class'].split()[1],'||', ha['title'],'||', p.a.text
		#print '###################################'
	#p=programs[0]
	#print p
	#print get_program('http://www.programme-tv.com'+p['url'])
	return programs

def forge_channel_url(channel, date):
	try:
		c = channels_by_ref[int(channel)]
	except ValueError:
		c = channels_by_name[channel.lower()]
	if args.debug: print c
	u = c['page'].split('/')
	u[2:2] = [date]
	u[0:0] = ['http://www.programme-tv.com']
	return '/'.join(u)
	#print get_channel_list()

def add_programs2db(db, channel, date, types, excludes):
	programs = get_program_list(channel, date, types, excludes)
	for p in programs:
		db_title = db.get_title(title = p['title'])
		if len(db_title) == 0:
			if p['title'] in default_excludes:
				banned = True
			else:
				banned = False
			id_serie = db.add_serie(banned)
			id_title = db.add_title(p['title'], id_serie)
		pass

def all_programs(date, delta, html, url, email, types, exclude):
	print (date, delta, html, url, email, types, exclude)
	datebase = datetime.datetime.strptime(date, '%d%m%Y').date()
	programs_by_name = {}
	full = u''
	anchor = 0
	print 'In all_programs'
	for channel in default_channels:
		for datedelta in range(delta):
			date = datebase+datetime.timedelta(datedelta)
			print '################################'
			print channel, date
			programs = get_program_list(channel, date.strftime('%d%m%Y'), types, exclude)
			for p in programs:
				print p
				title = p['title']
				saison = p['saison']
				episode = p['episode']
				if title not in programs_by_name:
					programs_by_name[title] = {}
				if saison not in programs_by_name[title]:
					programs_by_name[title][saison] = {}
				if episode == '':
					X = [x for x in programs_by_name[title][saison].keys() if x.find('No_episode_')]
					print 'No episode defined for ', p
					print X
					episode = 'No_episode_{0}'.format(len(X))
					print 'setting new episode string :', episode
				if episode not in programs_by_name[title][saison]:
					p['anchor'] = anchor
					programs_by_name[title][saison][episode] = p
					if html:
						full += "<a href='#top'>#</a>###############################<br/>\n"
					else:
						full += "################################\n"
					for f in ('title', 'saison', 'episode', 'channel', 'episode_title', 'date', 'heure', 'story', 'programme-suite'):
						if f in p:
							if html and f == 'title' :
								full += u"<a id=\"C{0}\">{1}</a> : {2}\n".format(anchor, f, p[f])
							else:
								full += u"{1} : {2}\n".format(anchor, f, p[f])
							if html:
								full += u"<br/>\n"
					anchor += 1

#				print '################################'
	if html:
		addr = url+os.path.basename(html)
		import codecs
		f = codecs.open(html, 'w', encoding='utf-8')
		html = '''
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<h1>Tv program from {0} ({1} days)</h1>
<a href="http://lbrarda.web.cern.ch/lbrarda/ptv.php">Programme-tv.com links here</a>
<a href="{2}"> Full listing there </a>
<p/>
		'''.format(datebase.strftime('%Y/%m/%d'), delta, addr)
		f.write('''
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<h1>Tv program from {0} ({1} days)</h1>
<a name="top"></a>
		'''.format(datebase.strftime('%Y/%m/%d'), delta))
	for p in sorted(programs_by_name.keys()):
#			print p
		saisons = []
		for s in programs_by_name[p]:
#				print s
			if html:
				episodes = u'Saison {0} Episode(s)'.format(s)
				for e in sorted(programs_by_name[p][s].keys()):
#						print e, programs_by_name[p][s][e]
					if 'anchor' in programs_by_name[p][s][e]:
						anchor = programs_by_name[p][s][e]['anchor']
					else:
						anchor = ''
					episodes += ' <a href="{0}#C{1}">{2}</a>'.format(addr, anchor, e)
				saisons.append(episodes)
			else:
				saisons.append(u'Saison {0} Episode(s) {1}'.format(s, ', '.join(sorted(programs_by_name[p][s].keys()))))
		if html:
			try:
				f.write( u'{0} ({1}<br/>'.format(p, '; '.join(sorted(saisons))))
				html += u'{0} ({1}<br/>'.format(p, '; '.join(sorted(saisons)))
			except UnicodeEncodeError:
				print 'UnicodeEncodeError'
				print type(p), p
				print saisons
		else:
			print u'{0} ({1}'.format(p, '; '.join(sorted(saisons)))
	if html:
		full += "cc###############################<br/>\n"
		f.write(full)
		html += full+'''

</body>
</html>
		'''
		f.write('''

</body>
</html>
		''')
		f.close()
		if email:
			import smtplib
			from email.mime.multipart import MIMEMultipart
			from email.mime.text import MIMEText
			msg = MIMEMultipart('alternative')
			msg['Subject'] = 'Tv program from {0} ({1} days)'.format(datebase.strftime('%Y/%m/%d'), delta)
			msg['From'] = 'loic.brarda@gmail.com'
			msg['To'] = email
			# Record the MIME types of both parts - text/plain and text/html.
			part1 = MIMEText('The program is in html form', 'plain')
			part2 = MIMEText(html, 'html', "utf-8")
			# Attach parts into message container.
			# According to RFC 2046, the last part of a multipart message, in this case
			# the HTML message, is best and preferred.
			msg.attach(part1)
			msg.attach(part2)

			# Send the message via local SMTP server.
			s = smtplib.SMTP('localhost')
			# sendmail function takes 3 arguments: sender's address, recipient's address
			# and message to send - here it is sent as one string.
			s.sendmail('loic.brarda@gmail.com', email, msg.as_string())
			s.quit()
	else:
		full += "################################\n"
		print full
#channels = {{u'150': {'name': u'VIER', 'img': u'http://static3.programme-tv.com//images/channels/150.gif', 'page': u'/chaine/150/programme-television-VIER.html'}, u'318': {'name': u'NT1', 'img': u'http://static3.programme-tv.com//images/channels/318.gif', 'page': u'/chaine/318/programme-television-NT1.html'}, u'313': {'name': u'EEN', 'img': u'http://static3.programme-tv.com//images/channels/313.gif', 'page': u'/chaine/313/programme-television-EEN.html'}, u'315': {'name': u'Public S\xe9nat - LCP AN', 'img': u'http://static3.programme-tv.com//images/channels/315.gif', 'page': u'/chaine/315/programme-television-Public-Senat--LCP-AN.html'}, u'67': {'name': u'CLUB RTL', 'img': u'http://static3.programme-tv.com//images/channels/67.gif', 'page': u'/chaine/67/programme-television-CLUB-RTL.html'}, u'69': {'name': u'FRANCE 5', 'img': u'http://static3.programme-tv.com//images/channels/69.gif', 'page': u'/chaine/69/programme-television-FRANCE-5.html'}, u'257': {'name': u'RTBF SAT.', 'img': u'http://static3.programme-tv.com//images/channels/257.gif', 'page': u'/chaine/257/programme-television-RTBF-SAT.html'}, u'24': {'name': u'RTBF 1', 'img': u'http://static3.programme-tv.com//images/channels/24.gif', 'page': u'/chaine/24/programme-television-RTBF-1.html'}, u'1': {'name': u'TF1', 'img': u'http://static3.programme-tv.com//images/channels/1.gif', 'page': u'/chaine/1/programme-television-TF1.html'}, u'27': {'name': u'TV5 MONDE FBS', 'img': u'http://static3.programme-tv.com//images/channels/27.gif', 'page': u'/chaine/27/programme-television-TV5-FBS.html'}, u'22': {'name': u'PARIS PREMIERE', 'img': u'http://static3.programme-tv.com//images/channels/22.gif', 'page': u'/chaine/22/programme-television-PARIS-PREMIERE.html'}, u'42': {'name': u'RTBF 2', 'img': u'http://static3.programme-tv.com//images/channels/42.gif', 'page': u'/chaine/42/programme-television-RTBF-2.html'}, u'41': {'name': u'RTL', 'img': u'http://static3.programme-tv.com//images/channels/41.gif', 'page': u'/chaine/41/programme-television-RTL.html'}, u'429': {'name': u'TV5 Monde', 'img': u'http://static3.programme-tv.com//images/channels/429.gif', 'page': u'/chaine/429/programme-television-TV5-Monde.html'}, u'3': {'name': u'FRANCE 3', 'img': u'http://static3.programme-tv.com//images/channels/3.gif', 'page': u'/chaine/3/programme-television-FRANCE-3.html'}, u'321': {'name': u'FRANCE 4', 'img': u'http://static3.programme-tv.com//images/channels/321.gif', 'page': u'/chaine/321/programme-television-FRANCE-4.html'}, u'402': {'name': u'TV8 MONT BLANC', 'img': u'http://static3.programme-tv.com//images/channels/402.gif', 'page': u'/chaine/402/programme-television-TV8-MONT-BLANC.html'}, u'1032': {'name': u'D8', 'img': u'http://static3.programme-tv.com//images/channels/1032.gif', 'page': u'/chaine/1032/programme-television-D8.html'}, u'1033': {'name': u'D17', 'img': u'http://static3.programme-tv.com//images/channels/1033.gif', 'page': u'/chaine/1033/programme-television-D17.html'}, u'717': {'name': u'RTBF 3', 'img': u'http://static3.programme-tv.com//images/channels/717.gif', 'page': u'/chaine/717/programme-television-RTBF-3.html'}, u'467': {'name': u'2BE', 'img': u'http://static3.programme-tv.com//images/channels/467.gif', 'page': u'/chaine/467/programme-television-2BE.html'}, u'463': {'name': u'VIVOLTA', 'img': u'http://static3.programme-tv.com//images/channels/463.gif', 'page': u'/chaine/463/programme-television-VIVOLTA.html'}, u'148': {'name': u'VTM', 'img': u'http://static3.programme-tv.com//images/channels/148.gif', 'page': u'/chaine/148/programme-television-VTM.html'}, u'70': {'name': u'TMC', 'img': u'http://static3.programme-tv.com//images/channels/70.gif', 'page': u'/chaine/70/programme-television-TMC.html'}, u'2': {'name': u'FRANCE 2', 'img': u'http://static3.programme-tv.com//images/channels/2.gif', 'page': u'/chaine/2/programme-television-FRANCE-2.html'}, u'221': {'name': u'KTO', 'img': u'http://static3.programme-tv.com//images/channels/221.gif', 'page': u'/chaine/221/programme-television-KTO.html'}, u'1046': {'name': u"L'EQUIPE HD", 'img': u'http://static3.programme-tv.com//images/channels/1046.gif', 'page': u'/chaine/1046/programme-television-L-EQUIPE-HD.html'}, u'13': {'name': u'M6', 'img': u'http://static3.programme-tv.com//images/channels/13.gif', 'page': u'/chaine/13/programme-television-M6.html'}, u'967': {'name': u'RTS UN', 'img': u'http://static3.programme-tv.com//images/channels/967.gif', 'page': u'/chaine/967/programme-television-RTS-UN.html'}, u'1047': {'name': u'6ter', 'img': u'http://static3.programme-tv.com//images/channels/1047.gif', 'page': u'/chaine/1047/programme-television-6TER.html'}, u'14': {'name': u'ARTE', 'img': u'http://static3.programme-tv.com//images/channels/14.gif', 'page': u'/chaine/14/programme-television-ARTE.html'}, u'1045': {'name': u'HD1', 'img': u'http://static3.programme-tv.com//images/channels/1045.gif', 'page': u'/chaine/1045/programme-television-HD1.html'}, u'16': {'name': u'CANAL +', 'img': u'http://static3.programme-tv.com//images/channels/16.gif', 'page': u'/chaine/16/programme-television-CANAL-PLUS.html'}, u'19': {'name': u'RTL TVI', 'img': u'http://static3.programme-tv.com//images/channels/19.gif', 'page': u'/chaine/19/programme-television-RTL-TVI.html'}, u'1049': {'name': u'RMC D?couverte', 'img': u'http://static3.programme-tv.com//images/channels/1049.gif', 'page': u'/chaine/1049/programme-television-RMC-DECOUVERTE.html'}, u'1048': {'name': u'Num?ro 23', 'img': u'http://static3.programme-tv.com//images/channels/1048.gif', 'page': u'/chaine/1048/programme-television-NUMERO-23.html'}, u'968': {'name': u'RTS DEUX', 'img': u'http://static3.programme-tv.com//images/channels/968.gif', 'page': u'/chaine/968/programme-television-RTS-DEUX.html'}, u'298': {'name': u'BE 1', 'img': u'http://static3.programme-tv.com//images/channels/298.gif', 'page': u'/chaine/298/programme-television-BE-1.html'}, u'296': {'name': u'VIJF', 'img': u'http://static3.programme-tv.com//images/channels/296.gif', 'page': u'/chaine/296/programme-television-VIJF.html'}, u'419': {'name': u'FRANCE 24', 'img': u'http://static3.programme-tv.com//images/channels/419.gif', 'page': u'/chaine/419/programme-television-FRANCE-24.html'}}

def ftp_put(host, username, password, file, path):
	print 'ftp_put:', (host, username, file, path)  #, password
	from ftplib import FTP
	ftp = FTP(host, username, password)
#	ftp.login()
	with open(file, 'rb') as f:
		ftp.storlines('STOR '+path+os.path.basename(file), f)
	ftp.quit()

if __name__ == '__main__':
	config = ConfigParser.ConfigParser()
	config.read([os.path.expanduser('~/.tvprogfr')])
	parser = argparse.ArgumentParser(description='retreive program schedule')
	parser.add_argument('-d', '--debug', action='store_true')
	subparsers = parser.add_subparsers(title='subcommands', dest='command')

	show_channels = subparsers.add_parser('show_channels')
	write_channels_file_parser = subparsers.add_parser('write_channels_file')
	channels2db_parser = subparsers.add_parser('channels2db')
#    show_user_parser.add_argument('user')

	show_all_user_parser = subparsers.add_parser('show_all_programs')
	show_all_user_parser.add_argument('-e', '--exclude', nargs='*', default=default_excludes)
	show_all_user_parser.add_argument('-t', '--types', nargs='*', default=['type-serie'])
	show_all_user_parser.add_argument('-a', '--date', default=datetime.date.today().strftime('%d%m%Y'))
	show_all_user_parser.add_argument('-r', '--range', default=22)
	show_all_user_parser.add_argument('-n', '--new', action='store_true')
	show_all_user_parser.add_argument('-w', '--html')
	show_all_user_parser.add_argument('-E', '--email')

	show_user_parser = subparsers.add_parser('show_programs')
	show_user_parser.add_argument('-c', '--channel', default='RTS UN')
	show_user_parser.add_argument('-a', '--date', default=datetime.date.today().strftime('%d%m%Y'))
	show_user_parser.add_argument('-e', '--exclude', nargs='*', default=default_excludes)
	show_user_parser.add_argument('-t', '--types', nargs='*', default=['type-serie'])

	programs2db_parser = subparsers.add_parser('programs2db')
	programs2db_parser.add_argument('-c', '--channel', default='RTS UN')
	programs2db_parser.add_argument('-a', '--date', default=datetime.date.today().strftime('%d%m%Y'))
	programs2db_parser.add_argument('-e', '--exclude', nargs='*', default=default_excludes)
	programs2db_parser.add_argument('-t', '--types', nargs='*', default=['type-serie'])

	cron_parser = subparsers.add_parser('cron')
	cron_parser.add_argument('-p', '--path', default=os.path.expanduser(config.get('html', 'path')))
	cron_parser.add_argument('-E', '--email', default=config.get('email', 'email'))

	args = parser.parse_args()
	today = datetime.date.today()

	if args.command == 'show_channels':
		channels_by_name, channels_by_ref = get_channel_list()
		for c in sorted(channels_by_name.keys()):
			print u'{0} ({1})'.format(c, channels_by_name[c]['ref'])
	elif args.command in ('channels2db', 'programs2db'):
		import tvdb
		channels_by_name, channels_by_ref = get_channel_list()
		db=tvdb.tvdb()
		if args.command == 'channels2db':
			for c in channels_by_name:
				db.add_channel(c, channels_by_name[c]['ref'], '')
		elif args.command == 'programs2db':
			add_programs2db(db, args.channel, args.date, args.types, args.exclude)
		db.close()
	elif args.command == 'write_channels_file':
		channels_by_name, channels_by_ref = get_channel_list()
		with open('channels.py', 'w') as f:
			f.write('channels_by_name = ' + str(channels_by_name) + '\n')
			f.write('channels_by_ref = ' + str(channels_by_ref) + '\n')
	elif args.command == 'show_programs':
		programs = get_program_list(args.channel, args.date, args.types, args.exclude)
		print '################################'
		for p in programs:
			for f in ('title', 'saison', 'episode', 'episode_title', 'date', 'heure', 'story', 'programme-suite'):
				if f in p:
					print f + ' : ', p[f]
		print '################################'
	#        get_program('http://www.programme-tv.com/television/118003659/Person-of-Interest-Braquages.html')
	elif args.command == 'show_all_programs':
		if args.new:
			args.date=(datetime.date.today()+datetime.timedelta(base_delta)).strftime('%d%m%Y')
			args.range = 1
		all_programs(args.date, int(args.range), args.html, config.get('html', 'url'), args.email, args.types, args.exclude)		
	elif args.command == 'cron':
		print 'In Cron'
		_dates = [ list(re.findall('tv-(\d{4})(\d{2})(\d{2})', x)[0]) for x in os.listdir(args.path)]
		if _dates == []:
			last_date = today
			delta = base_delta
		else:
			dates = [datetime.date(int(d[0]), int(d[1]), int(d[2])) for d in _dates]
#			print _dates, dates
			last_date = sorted(dates)[-1] + datetime.timedelta(1)
		print _dates

		new_date = today + datetime.timedelta(base_delta)
		delta = min(base_delta, (new_date - last_date).days)+1
		print 'today : {0}\tlast_date : {1}\tnew_date : {2}\tdelta : {3}'.format(today, last_date, new_date, delta)
		if delta == base_delta:
			last_date = today
		print last_date, delta
		filename = '{0}/tv-{1}.html'.format(args.path, new_date.strftime('%Y%m%d'))
		all_programs(last_date.strftime('%d%m%Y'), delta, filename, config.get('html', 'url'), args.email, ['type-serie'], default_excludes)
		ftp_put(config.get('ftp', 'host'), config.get('ftp', 'username'), config.get('ftp', 'password'), filename, config.get('ftp', 'path'))

